﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;
using Spring.Context;
using Spring.Context.Support;
using Spring.Dao;
using Spring.Data.NHibernate.Support;
using Spring.Transaction.Interceptor;
using Spring.Stereotype;
using Ic.Model;

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Engine;
using NHibernate.Criterion;
using NHibernate.Search;
using NHibernate.Search.Attributes;
using NHibernate.Search.Impl;
using NHibernate.Search.Store;
using NHibernate.Search.Backend;

using Lucene.Net.Analysis;
using Lucene.Net.QueryParsers;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Analysis.Cn;

namespace Ic.Dao
{
    [Repository]
    public class DaoSpring:HibernateDao, IDaoSpring
    {
        private string _message;
        public string GetMessage()
        {
            return _message;
        }


        /// <summary>
        /// 存
        /// </summary>
        [Transaction]
        public bool Save<T>(T ab)
        {
            try
            {
                CurrentSession.Save(ab);
                return true;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "Save<T>");
                return false;
            }

        }

        /// <summary>
        /// 批量存储
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        [Transaction]
        public bool BatchSave<T>(IList<T> list)
        {
            try
            {
                foreach (T obj in list)
                {
                    CurrentSession.Save(obj);                    
                }

                return true;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "BatchSave<T>");
                return false;
            }
        }

        /// <summary>
        /// 更新
        /// </summary>
        [Transaction]
        public bool Update<T>(T ab)
        {
            try
            {
                CurrentSession.SaveOrUpdate(ab);
                return true;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "Update<T>");
                return false;
            }
           
        }
        

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="ab"></param>
        [Transaction]
        public bool Delete<T>(T ab)
        {
            try
            {
                CurrentSession.Delete(ab);
                return true;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "Delete<T>");
                return false;
            }
        }

        /// <summary>
        /// 读
        /// </summary>
        [Transaction(ReadOnly = true)]
        public T LoadFromId<T>(int id)
        {
            try
            {
                T obj = CurrentSession.Load<T>(id);
                return obj;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "LoadFromId<T>");
                return default(T);
            }
        }

        /// <summary>
        /// 获取全部
        /// </summary>
        [Transaction(ReadOnly = true)]
        public new IList<T> GetAll<T>() where T : class
        {
            ICriteria criteria = CurrentSession.CreateCriteria<T>();
            return criteria.List<T>();
        }

        /// <summary>
        /// 查
        /// </summary>   
        [Transaction(ReadOnly = true)]
        public IList<T> SearchByWhere<T>(string where)
        {
            try
            {
                //有意思的模板反射哟~
                T obj = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString());

                string hql = string.Format("from {0} {1}",
                    obj.GetType().ToString(),
                    where.ToUpper().StartsWith("WHERE") ? where : "WHERE " + where);

                IList<T> list = CurrentSession.CreateQuery(hql).List<T>();
                return list;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "Search<T>(where)");
                return null;
            }

        }

        /// <summary>
        /// 查排序
        /// </summary>  
        [Transaction(ReadOnly = true)]
        public IList<T> SearchByWhereOrder<T>(string where, string propertyName, bool ascending)
        {
            try
            {
                //排序
                Order order = new Order(propertyName, ascending);
                //排序
                ICriteria ic = CurrentSession.CreateCriteria(typeof(T));
                ic.AddOrder(order);
                //表达式
                ICriterion exp = Expression.Sql(where);
                ic.Add(exp);

                return ic.List<T>();
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "SearchWithOrder<T>");
                return null;
            }
        }

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="Columns">列</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="pageIdx">页号</param>
        /// <param name="OrderColumn">排序列</param>
        /// <param name="orderType">true降序 false 升级</param>
        /// <param name="condition">条件</param>
        /// <returns>DataTable</returns>
        [Transaction(ReadOnly = true)]
        public DataTable GetPagerByStoreProc<T>(string TableName,string PrimaryKey,string Columns, int pageSize, int pageIdx
            , string OrderColumn, bool orderType, string condition)
        {
            return GetPageEntitesByStoredProc
                (TableName, PrimaryKey, Columns, OrderColumn, pageSize, pageIdx, orderType, condition);
        }
        
        /// <summary>
        /// 重载版本
        /// 表名，主键 由元标记(TableInfo)给出
        /// </summary>
        [Transaction(ReadOnly = true)]
        public DataTable GetPagerByStoreProc<T>(string Columns, int pageSize, int pageIdx
            , string OrderColumn, bool orderType, string condition)
        {
            MemberInfo info = typeof(T);
            var tableInfo = (TableInfoAttribute)Attribute.GetCustomAttribute
                (info, typeof(TableInfoAttribute));

            return GetPageEntitesByStoredProc
                (tableInfo.TableName, tableInfo.PrimaryKey, Columns, OrderColumn, pageSize, pageIdx, orderType, condition);
        }

        /// <summary>
        /// 重载版本
        /// 表名，主键，所有列 由元标记(TableInfo)给出
        /// </summary>
        [Transaction(ReadOnly = true)]
        public DataTable GetPagerByStoreProc<T>(int pageSize, int pageIdx
            , string OrderColumn, bool orderType, string condition)
        {
            MemberInfo info = typeof(T);
            var tableInfo = (TableInfoAttribute)Attribute.GetCustomAttribute
                (info, typeof(TableInfoAttribute));

            if (tableInfo == null)
                throw new ArgumentNullException(info.Name + "未设置TableInfo属性元标记");

            return GetPageEntitesByStoredProc
                (tableInfo.TableName, tableInfo.PrimaryKey, tableInfo.Columns, OrderColumn, pageSize, pageIdx, orderType, condition);
        }

        /// <summary>
        /// 获取记录数
        /// </summary>
        [Transaction(ReadOnly = true)]
        public int GetRecordCount<T>(string where)
        {
            string cols = "*";
            try
            {
                //DISTINCT统计
                bool distinct = false;
                if (cols.ToLower().StartsWith("distinct"))
                {
                    distinct = true;
                    string[] columns = cols.Replace("distinct", "").Split(',');
                    StringBuilder sb = new StringBuilder();
                    sb.Append("distinct ");
                    for (int i = 0; i < columns.Length; i++)
                        sb.Append("alia." + columns[i].Trim());
                    cols = sb.ToString().TrimEnd(',');
                }

                T obj = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString());
                string hql = "";
                if (where.Trim() == String.Empty)
                {
                    hql = string.Format("select count({1}) from {0} {2}",
                        obj.GetType().ToString(), cols
                        , (distinct ? "alia" : "")
                        );
                }
                else
                {
                    hql = string.Format("select count({2}) from {0} {3} {1}",
                        obj.GetType().ToString(),
                        where.ToUpper().StartsWith("WHERE") ? where : "WHERE " + where
                        , cols, (distinct ? "alia" : ""));
                }

                IQuery query = CurrentSession.CreateQuery(hql);
                object o = query.UniqueResult();
                return int.Parse(o.ToString());
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "GetRecordCount<T>");
                return 0;
            }            
        }

        /// <summary>
        /// 全文检索 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        [Transaction(ReadOnly = true)]
        public IList<T> FullTextSearch<T>(string query)
        {
            //生成字段列表
            object objTarget = Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString());
            PropertyInfo[] pps = objTarget.GetType().GetProperties();
            string fs = "";
            foreach (PropertyInfo p in pps)
            {
                var fieldAttr = p.GetCustomAttributes
                    (typeof(FieldAttribute), false);
                if (fieldAttr != null && fieldAttr.Length > 0)
                {
                    fs += p.Name + ",";
                }
            }
            string[] fields = fs.TrimEnd(',').Split(',');

            //中文拆词            
            ChineseAnalyzer cnAnalyzer = new ChineseAnalyzer();
            MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, cnAnalyzer);

            Query queryObj;
            try
            {
                queryObj = parser.Parse(query);
            }
            catch (ParseException)
            {
                return null;
            }
            //使用当前Session

            IFullTextSession fullTextSession
                = NHibernate.Search.Search.CreateFullTextSession(CurrentSession);
            IQuery nhQuery = fullTextSession.CreateFullTextQuery(queryObj, typeof(T));
            //结果
            IList<T> results = nhQuery.List<T>();        

            return results;
        }      


        /*---------- internal ---------*/
        #region internal
        private DataTable GetPageEntitesByStoredProc(string tableName, string Primarykeyname, string colName, string orderCol,
            int pageSize, int pageIdx, bool orderType, string condition)
        {
            IList result = new ArrayList();

            ISessionFactoryImplementor imp = (ISessionFactoryImplementor)SessionFactory;
            IDbConnection conn = imp.ConnectionProvider.GetConnection();
            IDbCommand cmd = imp.ConnectionProvider.GetConnection().CreateCommand();

            cmd.CommandText = "pagination";
            cmd.CommandType = CommandType.StoredProcedure;

            IDbDataParameter parameter = cmd.CreateParameter();
            parameter.ParameterName = "@tblName";
            parameter.Value = tableName;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@PrimaryKey";
            parameter.Value = Primarykeyname;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@strGetFields";
            parameter.Value = colName;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@fldName";
            parameter.Value = orderCol;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@PageSize";
            parameter.Value = pageSize;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@PageIndex";
            parameter.Value = pageIdx;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@OrderType";
            parameter.Value = orderType;
            cmd.Parameters.Add(parameter);

            parameter = cmd.CreateParameter();
            parameter.ParameterName = "@strWhere";
            parameter.Value = condition;
            cmd.Parameters.Add(parameter);

            try
            {
                cmd.Connection = conn;
                IDataReader rs = cmd.ExecuteReader();
                // 分割列
                string[] cols = SplitsColumnNames(colName, ',');
                // 数据表
                DataTable dt = new DataTable(tableName);
                foreach (string col in cols)
                    dt.Columns.Add(col);

                // 取数据

                while (rs.Read())
                {
                    // 创建行
                    DataRow row = dt.NewRow();
                    for (int i = 0; i < cols.Length; i++)
                        row[cols[i]] = rs.GetValue(i);
                    // 插入行
                    dt.Rows.Add(row);
                }
                // 返回结果集
                return dt;
            }
            catch (Exception ex)
            {
                _message = ex.Message; Tool.Logger.ErrorLog(ex.Source, ex.Message, "GetPageEntitesByStoredProc");
                return null;
            }
        }


        /// <summary>
        /// 将字符里的列表分解出来
        /// </summary>
        /// <returns></returns>
        private static string[] SplitsColumnNames(string columns, char separator)
        {
            return columns.Split(new char[] { separator });
        }

        #endregion
    }
}
